/*
 * Copyright 2010-2012 Susanta Tewari. <freecode4susant@users.sourceforge.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
* ReportGenerator.java
*
* Created on December 20, 2007, 1:59 AM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
 */
package gui.genomemap.report;

import fs.genomemap.FileSettings;

import genomemap.data.DNA_RegionUtil;
import genomemap.maps.FullHybridizationMapComponent;
import genomemap.maps.XMap;
import genomemap.worker.LHood;

import gui.genomemap.inputModel.AnnealIModel;
import gui.genomemap.outputModel.AnnealOModel;
import gui.genomemap.outputModel.ComGLHoodOModel;
import gui.genomemap.outputModel.ComJLHoodOModel;
import gui.genomemap.outputModel.ComPLHoodOModel;
import gui.genomemap.outputModel.OutputModel;
import gui.genomemap.outputModel.ProgCurveOModel;

import javautil.collections.ArrayUtil;
import javautil.lang.StringUtil;
import javautil.swing.FrameUtil;

import org.apache.ecs.html.B;
import org.apache.ecs.html.BR;
import org.apache.ecs.html.Body;
import org.apache.ecs.html.Caption;
import org.apache.ecs.html.H2;
import org.apache.ecs.html.H3;
import org.apache.ecs.html.Head;
import org.apache.ecs.html.Html;
import org.apache.ecs.html.I;
import org.apache.ecs.html.TD;
import org.apache.ecs.html.TH;
import org.apache.ecs.html.TR;
import org.apache.ecs.html.Table;
import org.apache.ecs.html.Title;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

import java.awt.Component;
import java.beans.PropertyVetoException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author stewari1
 */
public class ReportGenerator {

    /** Field description */
    private OutputModel outputModel = null;

    /** Field description */
    private final ViewerFrame viewerFrame = new ViewerFrame();

    /**
     * Creates a new instance of ReportGenerator
     * @param outputModel
     */
    public ReportGenerator(OutputModel outputModel) {

        this.outputModel = outputModel;

        viewerFrame.setTitle("Output Model Statistics");
        FrameUtil.centralize(viewerFrame, 60);
    }

    public void show() throws Exception {

        if (outputModel instanceof ComGLHoodOModel) {
            showComGLHoodOModel((ComGLHoodOModel) outputModel);
        }

        if (outputModel instanceof ComPLHoodOModel) {
            showComPLHoodOModel((ComPLHoodOModel) outputModel);
        }

        if (outputModel instanceof ComJLHoodOModel) {
            showComJLHoodOModel((ComJLHoodOModel) outputModel);
        }
    }

    public static void createFigure(ComGLHoodOModel outputModel, int figIndex) {

        if (figIndex == ComGLHoodOModel.FIG_GMAP) {

            int ch_id       = outputModel.getInputModel().getLinkageGroup();
            int[] geneOrder = outputModel.getInputModel().getOrder();
            XMap gMap       = null;

            if (outputModel.getOptionsModel().isCreatingMap()) {

                try {

                    Collection<String> headerSet                = new ArrayList<>();
                    Collection<Boolean> crossSet                = new ArrayList<>();
                    Collection<LinkedHashSet<String>> labelsSet = new ArrayList<>();

                    if (outputModel.getOptionsModel().isComparingPubMap()) {

                        headerSet.add("Published Map");
                        crossSet.add(new Boolean(true));
                        labelsSet.add(DNA_RegionUtil.getGeneLabels(ch_id,
                                ArrayUtil.sort(geneOrder)));
                    }

                    headerSet.add("Inferred Map");
                    labelsSet.add(DNA_RegionUtil.getGeneLabels(ch_id, geneOrder));

                    if (outputModel.getOptionsModel().isComparingSeqMap()) {

                        headerSet.add("Sequence Map");
                        crossSet.add(new Boolean(true));

                        int[] seqOrder = DNA_RegionUtil.getGeneSeqOrder(ch_id, geneOrder);

                        labelsSet.add(DNA_RegionUtil.getGeneLabels(ch_id, seqOrder));
                    }

                    gMap = new XMap();

                    gMap.setName("Genetic Map");
                    gMap.instantiate(labelsSet.toArray(new LinkedHashSet[0]),
                                     headerSet.toArray(new String[0]),
                                     ArrayUtil.getBooleanArray(crossSet.toArray(new Boolean[0])));

                } catch (Exception ex) {
                    Logger.getLogger(ReportGenerator.class.getName()).log(Level.SEVERE, null, ex);
                }

                if (gMap != null) {
                    outputModel.getFiguresMap().put(new Integer(figIndex), gMap);
                }
            }
        }
    }

    /**
     * Method description
     *
     * @param outputModel description
     * @param figIndex description
     */
    private static void createFigure(ComPLHoodOModel outputModel, int figIndex) {

        int ch_id        = outputModel.getInputModel().getLinkageGroup();
        int[] probeOrder = outputModel.getInputModel().getOrder();

        if (figIndex == ComPLHoodOModel.FIG_PMAP) {

            XMap pMap = null;

            if (outputModel.getOptionsModel().isComparingSeqMap()) {

                try {

                    String[] mapHeaders = { "Inferred Physical XMap",
                                            "Sequence Based Physical XMap" };
                    boolean[] anyCross                     = { true };
                    LinkedHashSet<String>[] labelSetsGiven = new LinkedHashSet[2];
                    int[] seqOrder = DNA_RegionUtil.getProbeSeqOrder(ch_id, probeOrder);

                    labelSetsGiven[0] = DNA_RegionUtil.getProbeLabels(ch_id, probeOrder);
                    labelSetsGiven[1] = DNA_RegionUtil.getProbeLabels(ch_id, seqOrder);
                    pMap              = new XMap();

                    pMap.setName("Physical Map");
                    pMap.instantiate(labelSetsGiven, mapHeaders, anyCross);

                    if (pMap != null) {
                        outputModel.getFiguresMap().put(new Integer(figIndex), pMap);
                    }

                } catch (Exception ex) {
                    Logger.getLogger(ReportGenerator.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }

        if (figIndex == ComPLHoodOModel.FIG_FULLMAP) {

            if (outputModel.getOptionsModel().isCreatingFullMap()) {

                FullHybridizationMapComponent fullMap = new FullHybridizationMapComponent(ch_id,
                                                            probeOrder);

                fullMap.setName("Full Map");


                // @todo ad exception to check if map construction failed
                outputModel.getFiguresMap().put(new Integer(figIndex), fullMap);
            }
        }
    }

    /**
     * Method description
     *
     * @param outputModel description
     * @param figIndex description
     */
    private static void createFigure(ComJLHoodOModel outputModel, int figIndex) {

        int ch_id        = outputModel.getInputModel().getLinkageGroup();
        int[] probeOrder = outputModel.getInputModel().getOrder();
        int[] geneOrder  = outputModel.getGeneOrder();

        if (figIndex == ComJLHoodOModel.FIG_IPMAP) {

            XMap ipMap = null;

            if (outputModel.getOptionsModel().isComparingProbeSeqMap()) {

                try {

                    String[] mapHeaders = { "Inferred Physical XMap",
                                            "Sequence Based Physical XMap" };
                    boolean[] anyCross                     = { true };
                    LinkedHashSet<String>[] labelSetsGiven = new LinkedHashSet[2];
                    int[] seqOrder = DNA_RegionUtil.getProbeSeqOrder(ch_id, probeOrder);

                    labelSetsGiven[0] = DNA_RegionUtil.getProbeLabels(ch_id, probeOrder);
                    labelSetsGiven[1] = DNA_RegionUtil.getProbeLabels(ch_id, seqOrder);
                    ipMap             = new XMap();

                    ipMap.setName("Integrated Physical Map");
                    ipMap.instantiate(labelSetsGiven, mapHeaders, anyCross);

                } catch (Exception ex) {
                    Logger.getLogger(ReportGenerator.class.getName()).log(Level.SEVERE, null, ex);
                }

                if (ipMap != null) {
                    outputModel.getFiguresMap().put(new Integer(figIndex), ipMap);
                }
            }
        }

        if (figIndex == ComJLHoodOModel.FIG_IGMAP) {

            XMap igMap                                  = null;
            Collection<String> headerSet                = new ArrayList<>();
            Collection<Boolean> crossSet                = new ArrayList<>();
            Collection<LinkedHashSet<String>> labelsSet = new ArrayList<>();

            if (outputModel.getOptionsModel().isComparingGenePubMap()) {

                headerSet.add("Published Map");
                crossSet.add(new Boolean(true));
                labelsSet.add(DNA_RegionUtil.getGeneLabels(ch_id, ArrayUtil.sort(geneOrder)));
            }

            headerSet.add("Inferred Map");
            labelsSet.add(DNA_RegionUtil.getGeneLabels(ch_id, geneOrder));

            if (outputModel.getOptionsModel().isComparingGeneSeqMap()) {

                headerSet.add("Sequence Map");
                crossSet.add(new Boolean(true));

                int[] seqOrder = DNA_RegionUtil.getGeneSeqOrder(ch_id, geneOrder);

                labelsSet.add(DNA_RegionUtil.getGeneLabels(ch_id, seqOrder));
            }

            if (labelsSet.size() > 1) {

                try {

                    igMap = new XMap();

                    igMap.setName("Integrated Genetic Map");
                    igMap.instantiate(labelsSet.toArray(new LinkedHashSet[0]),
                                      headerSet.toArray(new String[0]),
                                      ArrayUtil.getBooleanArray(crossSet.toArray(new Boolean[0])));

                } catch (Exception ex) {
                    Logger.getLogger(ReportGenerator.class.getName()).log(Level.SEVERE, null, ex);
                }

                if (igMap != null) {
                    outputModel.getFiguresMap().put(new Integer(figIndex), igMap);
                }
            }
        }

        if (figIndex == ComJLHoodOModel.FIG_IFULLMAP) {

            if (outputModel.getOptionsModel().isCreatingFullMap()) {

                FullHybridizationMapComponent fullMap = new FullHybridizationMapComponent(ch_id,
                                                            probeOrder);

                fullMap.setName("Full Map");


                // @todo ad exception to check if map construction failed
                outputModel.getFiguresMap().put(new Integer(figIndex), fullMap);
            }
        }
    }

    public static void createFigure(AnnealOModel outputModel, int figIndex) {

        int ch_id     = outputModel.getInputModel().getLinkageGroup();
        int lHoodType = ((AnnealIModel) outputModel.getInputModel()).getLhoodType();

        if (lHoodType == LHood.GLHOOD) {

            int[] geneOrder = outputModel.getInputModel().getOrder();

            if (figIndex == AnnealOModel.FIG_GMAP) {

                XMap gMap = null;

                if (outputModel.getOptionsModel().getGOutputOptionsModel().isCreatingMap()) {

                    try {

                        Collection<String> headerSet                = new ArrayList<>();
                        Collection<Boolean> crossSet                = new ArrayList<>();
                        Collection<LinkedHashSet<String>> labelsSet = new ArrayList<>();

                        if (outputModel.getOptionsModel().getGOutputOptionsModel()
                                .isComparingPubMap()) {

                            headerSet.add("Published Map");
                            crossSet.add(new Boolean(true));
                            labelsSet.add(DNA_RegionUtil.getGeneLabels(ch_id,
                                    ArrayUtil.sort(geneOrder)));
                        }

                        headerSet.add("Inferred Map");
                        labelsSet.add(DNA_RegionUtil.getGeneLabels(ch_id, geneOrder));

                        if (outputModel.getOptionsModel().getGOutputOptionsModel()
                                .isComparingSeqMap()) {

                            headerSet.add("Sequence Map");
                            crossSet.add(new Boolean(true));

                            int[] seqOrder = DNA_RegionUtil.getGeneSeqOrder(ch_id, geneOrder);

                            labelsSet.add(DNA_RegionUtil.getGeneLabels(ch_id, seqOrder));
                        }

                        gMap = new XMap();

                        gMap.setName("Genetic Map");
                        gMap.instantiate(
                            labelsSet.toArray(new LinkedHashSet[0]),
                            headerSet.toArray(new String[0]),
                            ArrayUtil.getBooleanArray(crossSet.toArray(new Boolean[0])));

                    } catch (Exception ex) {

                        Logger.getLogger(ReportGenerator.class.getName()).log(Level.SEVERE, null,
                                         ex);
                    }

                    if (gMap != null) {
                        outputModel.getFiguresMap().put(new Integer(figIndex), gMap);
                    }
                }
            }
        }

        if (lHoodType == LHood.PLHOOD) {

            int[] probeOrder = outputModel.getInputModel().getOrder();

            if (figIndex == AnnealOModel.FIG_PMAP) {

                XMap pMap = null;

                if (outputModel.getOptionsModel().getPOutputOptionsModel().isComparingSeqMap()) {

                    try {

                        String[] mapHeaders = { "Inferred Physical XMap",
                                                "Sequence Based Physical XMap" };
                        boolean[] anyCross                     = { true };
                        LinkedHashSet<String>[] labelSetsGiven = new LinkedHashSet[2];
                        int[] seqOrder = DNA_RegionUtil.getProbeSeqOrder(ch_id, probeOrder);

                        labelSetsGiven[0] = DNA_RegionUtil.getProbeLabels(ch_id, probeOrder);
                        labelSetsGiven[1] = DNA_RegionUtil.getProbeLabels(ch_id, seqOrder);

                        if (labelSetsGiven[1].isEmpty()) {

                            System.out.println(
                                "AnnealOModel.FIG_PMAP map could not be created as there no seq info avail.");

                            return;
                        }

                        pMap = new XMap();

                        pMap.setName("Physical Map");
                        pMap.instantiate(labelSetsGiven, mapHeaders, anyCross);

                        if (pMap != null) {
                            outputModel.getFiguresMap().put(new Integer(figIndex), pMap);
                        }

                    } catch (Exception ex) {

                        Logger.getLogger(ReportGenerator.class.getName()).log(Level.SEVERE, null,
                                         ex);
                    }
                }
            }

            if (figIndex == AnnealOModel.FIG_FULLMAP) {

                if (outputModel.getOptionsModel().getPOutputOptionsModel().isCreatingFullMap()) {

                    FullHybridizationMapComponent fullMap =
                        new FullHybridizationMapComponent(ch_id, probeOrder);

                    fullMap.setName("Full Map");


                    // @todo ad exception to check if map construction failed
                    outputModel.getFiguresMap().put(new Integer(figIndex), fullMap);
                }
            }
        }

        if (lHoodType == LHood.JLHOOD) {

            int[] probeOrder = outputModel.getInputModel().getOrder();
            int[] geneOrder  = outputModel.getInputModel().getOrder();

            if (figIndex == AnnealOModel.FIG_IPMAP) {

                XMap ipMap = null;

                if (outputModel.getOptionsModel().getJOutputOptionsModel()
                        .isComparingProbeSeqMap()) {

                    try {

                        String[] mapHeaders = { "Inferred Physical XMap",
                                                "Sequence Based Physical XMap" };
                        boolean[] anyCross                     = { true };
                        LinkedHashSet<String>[] labelSetsGiven = new LinkedHashSet[2];
                        int[] seqOrder = DNA_RegionUtil.getProbeSeqOrder(ch_id, probeOrder);

                        labelSetsGiven[0] = DNA_RegionUtil.getProbeLabels(ch_id, probeOrder);
                        labelSetsGiven[1] = DNA_RegionUtil.getProbeLabels(ch_id, seqOrder);

                        if (labelSetsGiven[1].isEmpty()) {

                            System.out.println(
                                "AnnealOModel.FIG_IPMAP map could not be created as there no seq info avail.");

                            return;
                        }

                        ipMap = new XMap();

                        ipMap.setName("Integrated Physical Map");
                        ipMap.instantiate(labelSetsGiven, mapHeaders, anyCross);

                    } catch (Exception ex) {

                        Logger.getLogger(ReportGenerator.class.getName()).log(Level.SEVERE, null,
                                         ex);
                    }

                    if (ipMap != null) {
                        outputModel.getFiguresMap().put(new Integer(figIndex), ipMap);
                    }
                }
            }

            if (figIndex == AnnealOModel.FIG_IGMAP) {

                Collection<String> headerSet                = new ArrayList<>();
                Collection<Boolean> crossSet                = new ArrayList<>();
                Collection<LinkedHashSet<String>> labelsSet = new ArrayList<>();

                if (outputModel.getOptionsModel().getJOutputOptionsModel()
                        .isComparingGenePubMap()) {

                    headerSet.add("Published Map");
                    crossSet.add(new Boolean(true));
                    labelsSet.add(DNA_RegionUtil.getGeneLabels(ch_id, ArrayUtil.sort(geneOrder)));
                }

                headerSet.add("Inferred Map");
                labelsSet.add(DNA_RegionUtil.getGeneLabels(ch_id, geneOrder));

                if (outputModel.getOptionsModel().getJOutputOptionsModel()
                        .isComparingGeneSeqMap()) {

                    headerSet.add("Sequence Map");
                    crossSet.add(new Boolean(true));

                    int[] seqOrder = DNA_RegionUtil.getGeneSeqOrder(ch_id, geneOrder);

                    labelsSet.add(DNA_RegionUtil.getGeneLabels(ch_id, seqOrder));
                }

                if (labelsSet.size() > 1) {

                    try {

                        XMap gMap = new XMap();

                        gMap.instantiate(
                            labelsSet.toArray(new LinkedHashSet[0]),
                            headerSet.toArray(new String[0]),
                            ArrayUtil.getBooleanArray(crossSet.toArray(new Boolean[0])));

                    } catch (Exception ex) {

                        Logger.getLogger(ReportGenerator.class.getName()).log(Level.SEVERE, null,
                                         ex);
                    }
                }
            }

            if (figIndex == AnnealOModel.FIG_IFULLMAP) {

                if (outputModel.getOptionsModel().getJOutputOptionsModel().isCreatingFullMap()) {

                    FullHybridizationMapComponent fullMap =
                        new FullHybridizationMapComponent(ch_id, probeOrder);

                    fullMap.setName("Full Map");


                    // @todo ad exception to check if map construction failed
                    outputModel.getFiguresMap().put(new Integer(figIndex), fullMap);
                }
            }
        }
    }

    public static void createFigure(ProgCurveOModel outputModel, int figIndex) {

        int ch_id = outputModel.getInputModel().getLinkageGroup();

        if (figIndex == ProgCurveOModel.FIG_PROG_CURVE) {


            // @todo replace filesettings by a generic Settings object
            Map<Integer, Integer> expProgCurveMap  = FileSettings.load().getExpProgCurveMap(ch_id);
            Map<Integer, Integer> estProgCurveMap  = new Hashtable<>();
            Iterator<AnnealOModel> itrAnnealOModel = outputModel.getAnnealOModelSet().iterator();

            while (itrAnnealOModel.hasNext()) {

                AnnealOModel annealOModel = itrAnnealOModel.next();
                int probeCount            = annealOModel.getInputModel().getOrderCount();
                int contigCount           = annealOModel.getContigCount();

                estProgCurveMap.put(new Integer(probeCount), new Integer(contigCount));
            }


            // draw the curve
            // create the XYDataset for expected and estimated curves
            XYSeries expProgCurveSeries = new XYSeries("Expected Progress Curve");
            Iterator<Integer> itrExp    = expProgCurveMap.keySet().iterator();

            while (itrExp.hasNext()) {

                Integer probeCount  = itrExp.next();
                Integer contigCount = expProgCurveMap.get(probeCount);

                expProgCurveSeries.add(probeCount, contigCount);
            }

            XYSeries estProgCurveSeries = new XYSeries("Estimated Progress Curve");
            Iterator<Integer> itrEst    = estProgCurveMap.keySet().iterator();

            while (itrEst.hasNext()) {

                Integer probeCount  = itrEst.next();
                Integer contigCount = estProgCurveMap.get(probeCount);

                estProgCurveSeries.add(probeCount, contigCount);
            }

            XYSeriesCollection dataset = new XYSeriesCollection();

            dataset.addSeries(expProgCurveSeries);
            dataset.addSeries(estProgCurveSeries);


            // chart
            JFreeChart chart      = ChartFactory.createXYLineChart("Progress Curve",    // chart title
                "Probe Count",    // x axis label
                "Contig Count",    // y axis label
                dataset,    // data
                PlotOrientation.VERTICAL, true,    // include legend
                true,    // tooltips
                false    // urls
                    );
            ChartPanel chartPanel = new ChartPanel(chart);

            chartPanel.setName("Progress Curve");
            outputModel.getFiguresMap().put(new Integer(figIndex), chartPanel);
        }
    }

    /**
     *
     * @param outputModel
     * @return
     */
    public static String createModelStat(ComGLHoodOModel outputModel) {


        // formatters
        DecimalFormat fmt        = new DecimalFormat("00.0E00");
        DecimalFormat mapInfoFmt = new DecimalFormat("0.####");
        DecimalFormat stdErrFmt  = new DecimalFormat("0000.00E0");
        Html html                = new Html();

        html.setPrettyPrint(true);

        String reportTitle = "Computation of Genetic Likelihood";


        // set the header : for browsers
        Head head = new Head();

        head.addElement(new Title(reportTitle));
        html.addElement(head);

        Body body = new Body();


        // report title
        body.addElement(new H2().addElement(reportTitle));


        // Summary Statistics:
        body.addElement(new H3().addElement("Summary Statistics:"));

        String mapInfo = " The GeneticMap has log-likelihood = "
                         + mapInfoFmt.format(outputModel.getLHood());

        if (outputModel.isComputedPValue()) {
            mapInfo += " and P-Value = " + mapInfoFmt.format(outputModel.getPValue());
        }

        mapInfo += "\n";

        body.addElement(mapInfo).addElement(new BR());


        // Statistics Table
        body.addElement(new H3().addElement("Statistics Table:"));

        Table table         = new Table(1);
        int ch_id           = outputModel.getInputModel().getLinkageGroup();
        int[] geneOrder     = outputModel.getInputModel().getOrder();
        double[] cProbArray = outputModel.getCProbEst();
        double[] recomArray = outputModel.getRecomArray();
        double[] seArray    = null;

        if (outputModel.isComputedSE()) {
            seArray = outputModel.getSeArray();
        }


        // get the gene labels
        String[] labelArray = DNA_RegionUtil.getGeneLabels(ch_id,
                                  ArrayUtil.sort(geneOrder)).toArray(new String[0]);


        // table caption: generate the table caption
        String tableHeader = "Genetic Map with Estimates of Exchange Probability(<i>c</i>)";

        if (outputModel.isComputedSE()) {
            tableHeader += ", its <i>Standard Error(&sigma)</i>";
        }

        tableHeader += " and Recombination Fraction (<i>r</i>) on Linkage Group-"
                       + StringUtil.getRoman(outputModel.getInputModel().getLinkageGroup())
                       + " of <i>N.crassa</i>";

        table.addElement(new Caption().addElement(tableHeader));


        // create the table header row
        TR hearderRow = new TR();

        hearderRow.addElement(new TH(new B("Genes")));
        hearderRow.addElement(new TH(new B(new I("c"))));
        hearderRow.addElement(new TH(new B(new I("r"))));

        if (outputModel.isComputedSE()) {
            hearderRow.addElement(new TH(new B(new I("&sigma"))));
        }

        table.addElement(hearderRow);


        // populate the table
        for (int index = 0; index < labelArray.length - 1; index++) {

            TR dataRow = new TR();

            dataRow.addElement(
                new TD(new I(labelArray[index]).addElement("--").addElement(
                    labelArray[index + 1])));
            dataRow.addElement(new TD(fmt.format(cProbArray[index])));
            dataRow.addElement(new TD(fmt.format(recomArray[index])));

            if (outputModel.isComputedSE()) {

                hearderRow.addElement(new TH(new B(new I("&sigma"))));
                dataRow.addElement(new TD(stdErrFmt.format(seArray[index])));
            }

            table.addElement(dataRow);
        }

        body.addElement(table);
        html.addElement(body);


        // System.out.println(html);
        String modelStat = html.toString();

        outputModel.setModelStat(modelStat);

        return modelStat;
    }

    /**
     *
     * @param outputModel
     * @return
     */
    public String getLatexSnippet(ComGLHoodOModel outputModel) {

        String latexTable   = "";
        int ch_id           = outputModel.getInputModel().getLinkageGroup();
        int[] geneOrder     = outputModel.getInputModel().getOrder();
        double[] cProbArray = outputModel.getCProbEst();
        double[] recomArray = outputModel.getRecomArray();
        double[] seArray    = null;

        if (outputModel.isComputedSE()) {
            seArray = outputModel.getSeArray();
        }


        // get the gene labels
        String[] labelArray = DNA_RegionUtil.getGeneLabels(ch_id,
                                  ArrayUtil.sort(geneOrder)).toArray(new String[0]);


        // formatters
        DecimalFormat fmt        = new DecimalFormat("00.0E00");
        DecimalFormat mapInfoFmt = new DecimalFormat("0.####");


        // helper variables
        String gap = " & ";
        int middle = (labelArray.length - 1) / 2;


        // generate the table header
        String tableHeader = "Genetic Map with Estimates of Exchange Probability($c$)";

        if (outputModel.isComputedSE()) {
            tableHeader += ", its \\mbox{Standard Error}($\\sigma_c$)";
        }

        tableHeader += " and Recombination Fraction ($r$) on Linkage Group-"
                       + StringUtil.getRoman(outputModel.getInputModel().getLinkageGroup())
                       + " of \\emph{N.crassa}";


        // mapInfo: lhood and pvalue(if computed)
        String mapInfo = " The GeneticMap has log-likelihood = "
                         + mapInfoFmt.format(outputModel.getLHood());

        if (outputModel.isComputedPValue()) {
            mapInfo += " and P-Value = " + mapInfoFmt.format(outputModel.getPValue());
        }

        mapInfo += "\n";


        // create the table structure
        latexTable += "\\begin{table}[h]\n" + "\\centering\n" + mapInfo
                      + "\\begin{minipage}{\\textwidth}\n" + "\\centering\n"
                      + "\\caption{\\protect \\centering \\textbf{" + tableHeader + "}}\n"
                      + "\\vspace{0.1in}\n";

        if (outputModel.isComputedSE()) {

            latexTable +=
                "\\begin{tabular}{|c|c|c|c|c|c|c|c|} \\hline\n"
                + "\\textbf{Genes} & \\textbf{$c$}\\footnote{ $c$, $\\sigma_c$ and $r$ correspond to the genetic interval formed by the genes at the current row and the following row } & \\textbf{$\\sigma_c$}& \\textbf{$r$}&\\textbf{Genes}\\footnote{comes after the first column for genes is completed} & \\textbf{$c$} & \\textbf{$\\sigma_c$} & \\textbf{$r$} \\\\ \\hline\n";

        } else {

            latexTable +=
                "\\begin{tabular}{|c|c|c|c|c|c|} \\hline\n"
                + "\\textbf{Genes} & \\textbf{$c$} & \\textbf{$r$}&\\textbf{Genes}\\footnote{comes after the first column for genes is completed} & \\textbf{$c$} & \\textbf{$r$} \\\\ \\hline\n";
        }


        // populate the table
        for (int index = 0; index < middle; index++) {

            latexTable += ("\\emph{" + labelArray[index] + "--" + labelArray[index + 1] + "}")
                          + gap + fmt.format(cProbArray[index]);

            if (outputModel.isComputedSE()) {
                latexTable += gap + fmt.format(seArray[index]);
            }

            latexTable += gap + fmt.format(recomArray[index]) + gap
                          + ("\\emph{" + labelArray[middle + index] + "--"
                             + labelArray[middle + index + 1] + "}") + gap
                                 + fmt.format(cProbArray[middle + index]);

            if (outputModel.isComputedSE()) {
                latexTable += gap + fmt.format(seArray[middle + index]);
            }

            latexTable += gap + fmt.format(recomArray[middle + index]) + "\\\\ \n";
        }

        latexTable += "\\hline\n\\end{tabular}\n\\end{minipage}\n\\end{table}\n \n";

        return latexTable;
    }

    /**
     * Method description
     *
     * @param outputModel description
     *
     * @throws Exception description
     */
    private void showComGLHoodOModel(ComGLHoodOModel outputModel) {

        createFigure(outputModel, ComGLHoodOModel.FIG_GMAP);
        createModelStat(outputModel);
    }

    /**
     * Method description
     *
     * @param outputModel description
     *
     * @throws Exception description
     */
    private void showComPLHoodOModel(ComPLHoodOModel outputModel) {

        createFigure(outputModel, ComPLHoodOModel.FIG_PMAP);
        createFigure(outputModel, ComPLHoodOModel.FIG_FULLMAP);
    }

    /**
     * Method description
     *
     * @param outputModel description
     *
     * @throws Exception description
     */
    private void showComJLHoodOModel(ComJLHoodOModel outputModel) {

        createFigure(outputModel, ComJLHoodOModel.FIG_IPMAP);
        createFigure(outputModel, ComJLHoodOModel.FIG_IGMAP);
        createFigure(outputModel, ComJLHoodOModel.FIG_IFULLMAP);
    }

    /**
     * the loaction would be (offset,offset)
     *
     * @param comp description
     * @param offset description
     */
    private void display(final Component comp, final int offset) {

        java.awt.EventQueue.invokeLater(new Runnable() {

            public void run() {

                ChildIFrame childFrame = new ChildIFrame();

                childFrame.getScrollPane().setViewportView(comp);
                childFrame.setLocation(offset, offset);
                viewerFrame.getDesktop().add(childFrame);

                try {
                    childFrame.setSelected(true);
                } catch (PropertyVetoException ex) {
                    ex.printStackTrace();
                }

                if (!viewerFrame.isVisible()) {
                    viewerFrame.setVisible(true);
                }
            }

        });
    }
}
